package messaging

import (
	"context"
	"fmt"
	"net"
	"strconv"
	"strings"
	"time"

	"gb28181/internal/manager"

	"github.com/zeromicro/go-zero/core/logx"
)

// MessageSender 消息发送器
type MessageSender struct {
	clientMgr         *manager.ClientManager
	connectionManager *ConnectionManager
	logger            logx.Logger
}

// NewMessageSender 创建新的消息发送器
func NewMessageSender(clientMgr *manager.ClientManager) *MessageSender {
	return &MessageSender{
		clientMgr:         clientMgr,
		connectionManager: NewConnectionManager(),
		logger:            logx.WithCallerSkip(1),
	}
}

// BuildSIPMessage 构建SIP格式消息
func (s *MessageSender) BuildSIPMessage(method, deviceID, body string) ([]byte, error) {
	// 获取设备信息
	device, exists := s.clientMgr.GetDevice(deviceID)
	if !exists {
		return nil, fmt.Errorf("设备不存在: %s", deviceID)
	}

	// 构建SIP URI
	sipURI := fmt.Sprintf("sip:%s@%s", deviceID, s.extractIPFromSIPUri(device.SipUri))
	
	// 构建From字段（服务器端）
	from := fmt.Sprintf("sip:gb28181-server@%s", s.getServerIP())
	
	// 构建To字段（设备端）
	to := sipURI
	
	// 生成Call-ID
	callID := fmt.Sprintf("%d@%s", time.Now().UnixNano(), s.getServerIP())
	
	// 生成CSeq
	cseq := strconv.FormatInt(time.Now().Unix(), 10)
	
	// 构建SIP消息
	var message strings.Builder
	
	// 起始行
	message.WriteString(fmt.Sprintf("%s %s SIP/2.0\r\n", method, sipURI))
	
	// Via字段
	message.WriteString(fmt.Sprintf("Via: SIP/2.0/UDP %s;branch=z9hG4bK%d;rport\r\n", 
		s.getServerIP(), time.Now().UnixNano()))
	
	// Max-Forwards
	message.WriteString("Max-Forwards: 70\r\n")
	
	// From
	message.WriteString(fmt.Sprintf("From: %s\r\n", from))
	
	// To
	message.WriteString(fmt.Sprintf("To: %s\r\n", to))
	
	// Call-ID
	message.WriteString(fmt.Sprintf("Call-ID: %s\r\n", callID))
	
	// CSeq
	message.WriteString(fmt.Sprintf("CSeq: %s %s\r\n", cseq, method))
	
	// Contact
	message.WriteString(fmt.Sprintf("Contact: %s\r\n", from))
	
	// User-Agent
	message.WriteString("User-Agent: GB28181-Server/1.0\r\n")
	
	// 如果有消息体
	if body != "" {
		message.WriteString("Content-Type: application/xml\r\n")
		message.WriteString(fmt.Sprintf("Content-Length: %d\r\n", len(body)))
		message.WriteString("\r\n")
		message.WriteString(body)
	} else {
		message.WriteString("Content-Length: 0\r\n")
		message.WriteString("\r\n")
	}
	
	return []byte(message.String()), nil
}

// extractIPFromSIPUri 从SIP URI中提取IP地址
func (s *MessageSender) extractIPFromSIPUri(sipUri string) string {
	parts := strings.Split(sipUri, "@")
	if len(parts) != 2 {
		return "127.0.0.1"
	}
	
	addressPart := parts[1]
	if strings.Contains(addressPart, ":") {
		return strings.Split(addressPart, ":")[0]
	}
	
	return addressPart
}

// getServerIP 获取服务器IP地址
func (s *MessageSender) getServerIP() string {
	// 这里简化处理，实际应该从配置中获取服务器IP
	// 暂时返回本地IP
	return "127.0.0.1:5060"
}

// SendSIPMessageToDevice 发送SIP格式消息到设备
func (s *MessageSender) SendSIPMessageToDevice(ctx context.Context, method, deviceID, body string) error {
	// 构建SIP消息
	sipMessage, err := s.BuildSIPMessage(method, deviceID, body)
	if err != nil {
		return fmt.Errorf("构建SIP消息失败: %v", err)
	}

	// 获取设备信息
	device, exists := s.clientMgr.GetDevice(deviceID)
	if !exists {
		return fmt.Errorf("设备不存在: %s", deviceID)
	}

	// 检查设备是否在线
	if !device.IsOnline() {
		return fmt.Errorf("设备不在线: %s", deviceID)
	}

	// 从SIP URI解析设备地址
	remoteAddr, err := s.parseSIPUri(device.SipUri)
	if err != nil {
		return fmt.Errorf("解析SIP URI失败: %v", err)
	}

	// 优先尝试通过连接管理器发送（复用连接）
	err = s.sendViaConnectionManager(deviceID, remoteAddr, sipMessage)
	if err == nil {
		s.logger.Infof("通过连接管理器发送SIP消息成功: 方法=%s, 设备=%s, 地址=%s", method, deviceID, remoteAddr)
		return nil
	}

	// 如果连接管理器失败，尝试直接发送
	s.logger.Errorf("连接管理器发送SIP消息失败，尝试直接发送: 方法=%s, 设备=%s, 错误=%v", method, deviceID, err)

	// 尝试通过TCP发送消息
	err = s.sendViaTCP(remoteAddr, sipMessage)
	if err == nil {
		s.logger.Infof("通过TCP发送SIP消息成功: 方法=%s, 设备=%s, 地址=%s", method, deviceID, remoteAddr)
		return nil
	}

	// 如果TCP失败，尝试通过UDP发送
	err = s.sendViaUDP(remoteAddr, sipMessage)
	if err == nil {
		s.logger.Infof("通过UDP发送SIP消息成功: 方法=%s, 设备=%s, 地址=%s", method, deviceID, remoteAddr)
		return nil
	}

	return fmt.Errorf("发送SIP消息失败: 所有方式都尝试失败，方法=%s, 设备=%s", method, deviceID)
}

// SendMessageToDevice 发送消息到设备
func (s *MessageSender) SendMessageToDevice(ctx context.Context, deviceID string, message []byte) error {
	// 获取设备信息
	device, exists := s.clientMgr.GetDevice(deviceID)
	if !exists {
		return fmt.Errorf("设备不存在: %s", deviceID)
	}

	// 检查设备是否在线
	if !device.IsOnline() {
		return fmt.Errorf("设备不在线: %s", deviceID)
	}

	// 从SIP URI解析设备地址
	remoteAddr, err := s.parseSIPUri(device.SipUri)
	if err != nil {
		return fmt.Errorf("解析SIP URI失败: %v", err)
	}

	// 优先尝试通过连接管理器发送（复用连接）
	err = s.sendViaConnectionManager(deviceID, remoteAddr, message)
	if err == nil {
		s.logger.Infof("通过连接管理器发送消息成功: 设备=%s, 地址=%s", deviceID, remoteAddr)
		return nil
	}

	// 如果连接管理器失败，尝试直接发送
	s.logger.Errorf("连接管理器发送失败，尝试直接发送: 设备=%s, 错误=%v", deviceID, err)

	// 尝试通过TCP发送消息
	err = s.sendViaTCP(remoteAddr, message)
	if err == nil {
		s.logger.Infof("通过TCP发送消息成功: 设备=%s, 地址=%s", deviceID, remoteAddr)
		return nil
	}

	// 如果TCP失败，尝试通过UDP发送
	err = s.sendViaUDP(remoteAddr, message)
	if err == nil {
		s.logger.Infof("通过UDP发送消息成功: 设备=%s, 地址=%s", deviceID, remoteAddr)
		return nil
	}

	return fmt.Errorf("发送消息失败: 所有方式都尝试失败，设备=%s", deviceID)
}

// parseSIPUri 解析SIP URI获取设备地址
func (s *MessageSender) parseSIPUri(sipUri string) (string, error) {
	// SIP URI格式: sip:device_id@ip:port
	parts := strings.Split(sipUri, "@")
	if len(parts) != 2 {
		return "", fmt.Errorf("无效的SIP URI格式: %s", sipUri)
	}

	// 提取IP:Port部分
	addressPart := parts[1]

	// 检查是否包含端口
	if !strings.Contains(addressPart, ":") {
		// 如果没有端口，使用默认端口5060
		addressPart += ":5060"
	}

	return addressPart, nil
}

// sendViaTCP 通过TCP发送消息
func (s *MessageSender) sendViaTCP(remoteAddr string, message []byte) error {
	// 建立TCP连接
	conn, err := net.DialTimeout("tcp", remoteAddr, 5*time.Second)
	if err != nil {
		return fmt.Errorf("TCP连接失败: %v", err)
	}
	defer conn.Close()

	// 设置写超时
	conn.SetWriteDeadline(time.Now().Add(5 * time.Second))

	// 发送消息
	_, err = conn.Write(message)
	if err != nil {
		return fmt.Errorf("TCP发送失败: %v", err)
	}

	return nil
}

// sendViaConnectionManager 通过连接管理器发送消息
func (s *MessageSender) sendViaConnectionManager(deviceID, remoteAddr string, message []byte) error {
	// 优先尝试TCP连接
	_, err := s.connectionManager.GetOrCreateConnection(deviceID, "tcp", remoteAddr)
	if err != nil {
		// 如果TCP失败，尝试UDP连接
		_, err = s.connectionManager.GetOrCreateConnection(deviceID, "udp", remoteAddr)
		if err != nil {
			return fmt.Errorf("无法建立TCP或UDP连接: %v", err)
		}
	}

	// 通过连接发送消息
	err = s.connectionManager.SendMessage(deviceID, message)
	if err != nil {
		return fmt.Errorf("通过连接发送消息失败: %v", err)
	}

	return nil
}

// sendViaUDP 通过UDP发送消息
func (s *MessageSender) sendViaUDP(remoteAddr string, message []byte) error {
	// 解析UDP地址
	udpAddr, err := net.ResolveUDPAddr("udp", remoteAddr)
	if err != nil {
		return fmt.Errorf("解析UDP地址失败: %v", err)
	}

	// 建立UDP连接
	conn, err := net.DialUDP("udp", nil, udpAddr)
	if err != nil {
		return fmt.Errorf("UDP连接失败: %v", err)
	}
	defer conn.Close()

	// 设置写超时
	conn.SetWriteDeadline(time.Now().Add(5 * time.Second))

	// 发送消息
	_, err = conn.Write(message)
	if err != nil {
		return fmt.Errorf("UDP发送失败: %v", err)
	}

	return nil
}

// SendMessageWithRetry 带重试的消息发送
func (s *MessageSender) SendMessageWithRetry(ctx context.Context, deviceID string, message []byte, maxRetries int) error {
	var lastErr error

	for i := 0; i < maxRetries; i++ {
		err := s.SendMessageToDevice(ctx, deviceID, message)
		if err == nil {
			return nil
		}

		lastErr = err
		s.logger.Errorf("消息发送失败(尝试 %d/%d): %v", i+1, maxRetries, err)

		// 等待一段时间后重试
		time.Sleep(time.Duration(i+1) * time.Second)
	}

	return fmt.Errorf("消息发送失败，重试%d次后仍然失败: %v", maxRetries, lastErr)
}

// BroadcastMessage 广播消息到多个设备
func (s *MessageSender) BroadcastMessage(ctx context.Context, deviceIDs []string, message []byte) map[string]error {
	results := make(map[string]error)

	for _, deviceID := range deviceIDs {
		err := s.SendMessageToDevice(ctx, deviceID, message)
		results[deviceID] = err

		if err != nil {
			s.logger.Errorf("广播消息到设备失败: 设备=%s, 错误=%v", deviceID, err)
		} else {
			s.logger.Infof("广播消息到设备成功: 设备=%s", deviceID)
		}
	}

	return results
}
